﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace evolutionary_algorithm
{
    class Genetic : Algorithm
    {
        public Genetic(int individuals, int genes)
        {
            /*
             * Konstruktor klasy Genetic
             * Przypisujemy zmiennym ilosc osobnikow i liczbe ich genów.
             * Ustawiamy wzorzec
             * Ustawiamy wielkość tablicom parents.
             * Ustawiamy tablice fitness
             * Uruchamiamy funkcję losującą.
             */
            this.individuals = individuals;
            this.genes = genes;

            model = new double[16] { 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 };
            parents = new double[this.individuals, this.genes];
            fitnessParents = new double[this.individuals];
            
            randomGenes(); //Losowanie genów dla osobników
            setDraw(); //Ustawianie tablicy do losowania (wg. najbardziej zbliżonych genów)
        }
        
        private void randomGenes()
        {
            /*
             * Losowanie genów
             */
            for (int i = 0; i < this.individuals; i++)
            {
                for (int j = 0; j < this.genes; j++)
                {
                    parents[i, j] = (byte)this.r.Next(0, 2); //Losowanie liczby z przedzialu 0-1
                }
                setFitnessParents(i);
            }
        }

        public void mutation()
        {
            /*
             *wylosowac ilosc osobnikow do mutacji(ok. 4%) 
             * wylosowac gen do mutacji
             * sprawdzic biezacy gen a nastepnie wstawic wartosc przeciwna
             * 
             */

            //zmienna hMG okresla ilość genow w danym osobniku, która zostanie zmodyfikowana
            int hMG = this.r.Next(1, 3);
            int currentGene;

            //pierwszy i drugi for służy do przeszukiwania tablicy z osobnikami
            for (int i = 0; i < individuals; i++)
            {
                //instrukcja warunkowa losuje liczbe (zaokraglona do dwoch miejsc po przecinku) po czym sprawdza ja z wartoscia(0.04)
                //poniewaz r.NextDouble() przyjmuje wartosci od 0 do 1, mozna ją zastosowac do wyznaczania czynnika losujacego (szczescia) 
                //Jeszcze mam pewne watpliwosci co do znaku dzielacego liczbe okreslona wraz z wylosowana. Zastanawiam sie czy nie powinien
                //byc tam znak mniejszy, badz rowny od (<)
                if (r.NextDouble() <= 0.04)
                {
                    for (int j = 0; j < hMG; j++)
                    {
                        //losowanie konkretnego genu
                        currentGene = r.Next(0, genes);
                        Console.WriteLine("MUTACJA");
                        //mutacja wylosowanego genu, jezeli wczesniej wartosc byla rowna 0, po operacji przyjmie 1 i odwrotnie
                        parents[i, currentGene] = parents[i, currentGene] == 0 ? 1 : 0;
                    }
                    //liczmy fitness dla danego wiersza
                    setFitnessParents(i);
                }
            }
            //po przeszukaniu "rodziców" generujemy na nowo tablicę do losowania
            setDraw();
            statisticsOfFitness();
        }

        public void changeOneGene()
        {
            /*
             * Funkcja stosowana tylko wtedy, gdy jeden gen jest niezgodny z wzorcem
             */
            for (int j = 0; j < genes; j++)
            {
                parents[iGWOI, j] = parents[iGWOI, j] == 0 ? 1 : 0;
                if (haveFound() == 1)
                    break;
                else
                    parents[iGWOI, j] = parents[iGWOI, j] == 0 ? 1 : 0;
            }
        }
    }
}
